/**
 * 1st . my function always return successfully , unless exit()
*/
#include <stdio.h>
#include <string.h>

#ifndef __LIST__
#define __LIST__

#ifdef __cplusplus
extern "C" {
#endif

typedef struct _list_node {
	struct _list_node * prev; /* it's the first item in the root for ever */
	struct _list_node * next; /* it's the last  item in the root for ever */
	void * 	data;
	unsigned int size;
	int type;
} LIST_NODE;

typedef struct {
	LIST_NODE root;
	LIST_NODE * curr_node;
	int list_lock;
	unsigned int list_num;
} LIST_ROOT;

#define FROM_HEAD 0
#define FROM_TAIL 1

# define Error_Rpt(CONTENT,...)							\
	fprintf( 	stderr , 						\
			CONTENT" -- %s %s:%d	\n" ,				\
			##__VA_ARGS__ ,						\
			__FILE__ , 						\
			__FUNCTION__ , 						\
			__LINE__ );						\


#define ASSERT( POINTER )							\
	if( NULL == POINTER ) {							\
		Error_Rpt("Pointer is NULL");					\
		exit(-1);							\
	}									\

#define ASSERT_ALARM( POINTER )							\
	if( NULL == (void *)(POINTER) ) {					\
		Error_Rpt("Pointer is NULL");					\
		break;								\
	}									\


#define MALLOC_ITEM( TMP_P , ITEM_SIZE )					\
	TMP_P = (void *)malloc( ITEM_SIZE );					\
	ASSERT( TMP_P );							\
	memset(TMP_P , 0 , ITEM_SIZE );						\

	
#define FREE_ITEM( TMP_P )							\
	ASSERT(TMP_P);								\
	free( TMP_P );								\


#define CREATE_COPY_ITEM( ITEM_DEST_P , ITEM_SRC_P , SIZE )			\
	ASSERT( ITEM_SRC_P );							\
	MALLOC_ITEM( ITEM_DEST_P , SIZE );					\
	memcpy( ITEM_DEST_P , ITEM_SRC_P , SIZE );				\


#define LIST_INIT( ROOT ) 							\
	LIST_ROOT ROOT= 							\
		{ {&ROOT.root, &ROOT.root} , &ROOT.root , 0 , 0 };	 	\

#define EXTERN_LIST( ROOT )							\
	extern LIST_ROOT ROOT;							\

#ifndef LIST_FUNC
#define LIST_MACRO

#define RESET_CURR( ROOT_P )							\
	(ROOT_P)->curr_node = &(ROOT_P)->root;

#define SET_CURR( ROOT_P , CURR_P)						\
	(ROOT_P)->curr_node = CURR_P;

#define RET_CURR( ROOT_P )							\
	((ROOT_P)->curr_node)							\

#define NEXT_CURR( ROOT_P )							\
	(ROOT_P)->curr_node = (ROOT_P)->curr_node->next;			\

#define PREV_CURR( ROOT_P )							\
	(ROOT_P)->curr_node = (ROOT_P)->curr_node->prev;			\


#define LIST_SIZE( ROOT_P )							\
	(ROOT_P)->list_num							\

#define LIST_INC_NODE( ROOT_P )							\
	(ROOT_P)->list_num ++;							\

#define LIST_DEC_NODE( ROOT_P )							\
/*	RESET_CURR( ROOT_P );							*/\
	(ROOT_P)->list_num --;							\

#define LIST_EMPTY( ROOT_P )							\
	( (ROOT_P)->root.prev == &(ROOT_P)->root || 				\
	  (ROOT_P)->root.next == &(ROOT_P)->root )				\

#define LIST_ATROOT( ROOT_P , ITEM_P)						\
	( (ITEM_P) == &(ROOT_P)->root )						\

#define LIST_FOREACH_BEGIN( ROOT_P , ITEM_P )					\
	do {									\
		LIST_NODE * ITEM_P , ITEM ;					\
										\
		if( LIST_EMPTY( ROOT_P ) ) {					\
										\
			ITEM_P = NULL;						\
			break;							\
		}								\
										\
		for( ITEM_P =  (ROOT_P)->root.next ;		\
		     ITEM_P != &(ROOT_P)->root ; 		\
		     ITEM_P =  ITEM.next			\
		){								\
			ITEM = *ITEM_P;				\
		
		
		
#define LIST_FOREACH_END( ROOT_P )						\
		}								\
	} while(0); /* End foreach (ROOT_P) */					\

/* list function is writed by macro */
#define LIST_ADD_HEAD( ROOT_P , ITEM_P , SIZE , TYPE )				\
	do {									\
		LIST_NODE * ITEM_TMP_P ; 					\
										\
		ASSERT_ALARM( ITEM_P );						\
		ASSERT_ALARM( SIZE );						\
										\
		MALLOC_ITEM( ITEM_TMP_P , sizeof(LIST_NODE) );			\
										\
		CREATE_COPY_ITEM( ITEM_TMP_P->data , ITEM_P , SIZE );		\
										\
		ITEM_TMP_P->size = SIZE;					\
		ITEM_TMP_P->type = TYPE;					\
										\
		ITEM_TMP_P->prev = &(ROOT_P)->root ;				\
		ITEM_TMP_P->next = (ROOT_P)->root.next ;			\
		(ROOT_P)->root.next->prev = ITEM_TMP_P ;			\
		(ROOT_P)->root.next = ITEM_TMP_P;				\
										\
		LIST_INC_NODE( ROOT_P )						\
										\
	} while(0);								\


#define LIST_ADD_TAIL( ROOT_P , ITEM_P , SIZE , TYPE )				\
	do {									\
		LIST_NODE * ITEM_TMP_P;						\
										\
		ASSERT_ALARM( ITEM_P );						\
		ASSERT_ALARM( SIZE );						\
										\
		MALLOC_ITEM(ITEM_TMP_P , sizeof(LIST_NODE));			\
										\
		CREATE_COPY_ITEM( ITEM_TMP_P->data , ITEM_P , SIZE );		\
										\
		ITEM_TMP_P->size = SIZE;					\
		ITEM_TMP_P->type = TYPE;					\
										\
		ITEM_TMP_P->prev = (ROOT_P)->root.prev ;			\
		ITEM_TMP_P->next = &(ROOT_P)->root;				\
		(ROOT_P)->root.prev->next = ITEM_TMP_P;				\
		(ROOT_P)->root.prev = ITEM_TMP_P;				\
										\
		LIST_INC_NODE( (ROOT_P) );					\
										\
	} while(0);								\

#define LIST_ADD_BEFORE( ROOT_P , ITEM_SRC_P , ITEM_P , SIZE , TYPE )		\
	do {									\
		LIST_NODE * ITEM_TMP_P;						\
										\
		ASSERT_ALARM( ITEM_SRC_P );					\
		ASSERT_ALARM( ITEM_P );						\
		ASSERT_ALARM( SIZE );						\
										\
		MALLOC_ITEM(ITEM_TMP_P , sizeof(LIST_NODE));			\
										\
		CREATE_COPY_ITEM( ITEM_TMP_P->data , ITEM_P , SIZE );		\
										\
		ITEM_TMP_P->size = SIZE;					\
		ITEM_TMP_P->type = TYPE;					\
										\
		if (LIST_ATROOT( ROOT_P , ITEM_SRC_P ) ){			\
			LIST_ADD_HEAD( ROOT_P , ITEM_P , SIZE , TYPE );		\
			break;							\
		}								\
										\
		LIST_NODE * __ITEM_P_TMP;					\
		LIST_FOREACH_BEGIN( (ROOT_P) , __ITEM_P_TMP)			\
										\
			if( __ITEM_P_TMP == ITEM_SRC_P ){			\
										\
				ITEM_SRC_P->prev->next = ITEM_TMP_P;		\
				ITEM_TMP_P->prev = ITEM_SRC_P->prev;		\
				ITEM_TMP_P->next = ITEM_SRC_P;			\
				ITEM_SRC_P->prev = ITEM_TMP_P;			\
										\
				LIST_INC_NODE( ROOT_P );			\
				break;						\
			}							\
										\
		LIST_FOREACH_END((ROOT_P));					\
										\
	} while(0);								\

#define LIST_ADD_AFTER( ROOT_P , ITEM_SRC_P , ITEM_P , SIZE , TYPE )		\
	do {									\
		LIST_NODE * ITEM_TMP_P;						\
										\
		ASSERT_ALARM( ITEM_SRC_P );					\
		ASSERT_ALARM( ITEM_P );						\
		ASSERT_ALARM( SIZE );						\
										\
		MALLOC_ITEM(ITEM_TMP_P , sizeof(LIST_NODE));			\
										\
		CREATE_COPY_ITEM( ITEM_TMP_P->data , ITEM_P , SIZE );		\
										\
		ITEM_TMP_P->size = SIZE;					\
		ITEM_TMP_P->type = TYPE;					\
										\
		if (LIST_ATROOT( ROOT_P , ITEM_SRC_P ) ){			\
			LIST_ADD_HEAD( ROOT_P , ITEM_P , SIZE , TYPE );		\
			break;							\
		}								\
										\
		LIST_NODE * __ITEM_P_TMP;					\
		LIST_FOREACH_BEGIN( (ROOT_P) , __ITEM_P_TMP)			\
										\
			if( __ITEM_P_TMP == ITEM_SRC_P ){			\
										\
				ITEM_SRC_P->next->prev = ITEM_TMP_P;		\
				ITEM_TMP_P->next = ITEM_SRC_P->next;		\
				ITEM_TMP_P->prev = ITEM_SRC_P;			\
				ITEM_SRC_P->next = ITEM_TMP_P;			\
										\
				LIST_INC_NODE( ROOT_P );			\
				break;						\
			}							\
										\
		LIST_FOREACH_END((ROOT_P));					\
										\
										\
	} while(0);								\

#define LIST_DEL_HEAD( ROOT_P )							\
	do {									\
		if( LIST_EMPTY( ROOT_P ) ){					\
			break;							\
		}								\
										\
		LIST_NODE * head_tmp = (ROOT_P)->root.next ;			\
										\
		(ROOT_P)->root.next = (ROOT_P)->root.next->next ;		\
		(ROOT_P)->root.next->prev = &(ROOT_P)->root;			\
										\
		FREE_ITEM( head_tmp->data );					\
		FREE_ITEM( head_tmp ) ;						\
										\
		LIST_DEC_NODE( (ROOT_P) ) ;					\
	} while(0);

#define LIST_DEL_TAIL( ROOT_P )							\
	do {									\
		if( LIST_EMPTY((ROOT_P)) ){					\
			break;							\
		}								\
										\
		LIST_NODE * tail_tmp = (ROOT_P)->root.prev ;			\
										\
		(ROOT_P)->root.prev = (ROOT_P)->root.prev->prev ;		\
		(ROOT_P)->root.prev->next=&(ROOT_P)->root;			\
										\
		FREE_ITEM( tail_tmp->data );					\
		FREE_ITEM( tail_tmp );						\
										\
		LIST_DEC_NODE( (ROOT_P) );					\
	} while(0);								\

#define LIST_DEL_ITEM( ROOT_P , ITEM_P )					\
	do {									\
		ASSERT_ALARM( ITEM_P )						\
										\
		if( LIST_EMPTY( ROOT_P ) ){					\
			break;							\
		}								\
										\
		if( LIST_ATROOT( ROOT_P , ITEM_P ) ){				\
			break;							\
		}								\
										\
		LIST_NODE * ITEM_P##_TMP;					\
										\
		LIST_FOREACH_BEGIN( (ROOT_P) , ITEM_P##_TMP)			\
										\
			if( ITEM_P##_TMP == ITEM_P ){				\
										\
				ITEM_P->prev->next=ITEM_P->next;		\
				ITEM_P->next->prev=ITEM_P->prev;		\
										\
				FREE_ITEM( ITEM_P->data );			\
				FREE_ITEM( ITEM_P );				\
										\
				LIST_DEC_NODE( (ROOT_P) );			\
										\
				ITEM_P = NULL;					\
										\
				break;						\
			}							\
										\
		LIST_FOREACH_END((ROOT_P));					\
										\
	} while(0);

#define LIST_NEXT_NORET( ROOT_P )						\
	if( LIST_EMPTY((ROOT_P)) ) {						\
		break;								\
	}									\
	NEXT_CURR( ROOT_P )							\
	if( LIST_ATROOT( (ROOT_P) , RET_CURR(ROOT_P) ) ){			\
		NEXT_CURR( ROOT_P )						\
	}									\

#define LIST_NEXT( ROOT_P , ITEM_P_P )						\
	do {									\
		ASSERT_ALARM( ITEM_P_P );					\
		LIST_NEXT_NORET( ROOT_P );					\
		*(ITEM_P_P) = (ROOT_P)->curr_node;				\
										\
	} while(0);

#define LIST_PREV_NORET( ROOT_P )						\
	if( LIST_EMPTY( ROOT_P ) ) {						\
		break;								\
	} 									\
	PREV_CURR( ROOT_P );							\
	if( LIST_ATROOT( (ROOT_P) , RET_CURR(ROOT_P) ) ){			\
		PREV_CURR( ROOT_P );						\
	}									\
	
#define LIST_PREV( ROOT_P , ITEM_P_P )						\
	do {									\
		ASSERT_ALARM( ITEM_P_P );					\
		LIST_PREV_NORET( ROOT_P );					\
		*(ITEM_P_P) = (ROOT_P)->curr_node;				\
	} while(0);
	

#define LIST_LOCATE_LOOP( ROOT_P , NUM , ITEM_P_P )				\
	do{									\
		ASSERT_ALARM( ITEM_P_P );					\
		if( 0 == (NUM) ){						\
			*(ITEM_P_P) = NULL;					\
			break;							\
		}								\
		int __LIST_NUM_TEMP;						\
										\
		RESET_CURR( (ROOT_P) );						\
		for( 	__LIST_NUM_TEMP = 0 ;					\
			__LIST_NUM_TEMP < (NUM);				\
			__LIST_NUM_TEMP ++ ){					\
			LIST_NEXT_NORET( ROOT_P );				\
		}								\
										\
		*(ITEM_P_P) = RET_CURR( ROOT_P );				\
		if( *(ITEM_P_P) == &(ROOT_P)->root ){				\
			*(ITEM_P_P) = NULL;					\
		}								\
	}while(0);								\

#define LIST_PUSH_HEAD		LIST_ADD_HEAD

#define LIST_POP_HEAD( ROOT_P , ITEM_P )					\
	do{									\
		if( LIST_EMPTY((ROOT_P)) ) {					\
			break;							\
		}								\
		memcpy( ITEM_P , ROOT_P->root.next->data , ROOT_P->root.next->size);\
		LIST_DEL_HEAD( ROOT_P );					\
	}while(0);
	
#define LIST_PUSH_TAIL		LIST_ADD_TAIL

#define LIST_POP_TAIL
#else 

/* list function is writed by functions */
/* start LIST_FUNC */
#undef ASSERT_ALARM
#define ASSERT_ALARM( POINTER )	\
	assert( POINTER );

typedef int  (*	FOREACH_FUNCTION )( LIST_ROOT* root_p , LIST_NODE * node , void * data ) ;

inline int LIST_ATROOT( LIST_ROOT * ROOT_P , LIST_NODE * ITEM_P ){
	ASSERT_ALARM( ROOT_P );
	ASSERT_ALARM( ITEM_P );
	return (ITEM_P == &ROOT_P->root);
}

inline unsigned int LIST_SIZE( LIST_ROOT * ROOT_P ){
	ASSERT_ALARM( ROOT_P );
	return ROOT_P->list_num;
}

inline int LIST_EMPTY( LIST_ROOT * ROOT_P ){
	ASSERT_ALARM( ROOT_P );
	return ( (ROOT_P->root.prev == &ROOT_P->root) || 
		 (ROOT_P->root.next == &ROOT_P->root) );
}

inline unsigned int LIST_INC_NODE( LIST_ROOT * ROOT_P ){
	ASSERT_ALARM( ROOT_P );
	return ( ++ROOT_P->list_num );
}

inline unsigned int LIST_DEC_NODE( LIST_ROOT * ROOT_P ){
	ASSERT_ALARM( ROOT_P );
	return ( --ROOT_P->list_num );
}

inline void SET_CURR( LIST_ROOT * ROOT_P , LIST_NODE * CURR_P){
	ASSERT_ALARM( ROOT_P );
	ASSERT_ALARM( CURR_P );
	ROOT_P->curr_node = CURR_P;
	return ;
}

inline LIST_NODE * RET_CURR( LIST_ROOT * ROOT_P ){
	ASSERT_ALARM( ROOT_P );
	return ROOT_P->curr_node;
}

inline void RESET_CURR( LIST_ROOT * ROOT_P ){
	ASSERT_ALARM( ROOT_P );
	SET_CURR( ROOT_P , &ROOT_P->root);
	return ;
}

inline void NEXT_CURR( LIST_ROOT * ROOT_P ){
	ASSERT_ALARM( ROOT_P );
	do{
		SET_CURR( ROOT_P , RET_CURR(ROOT_P)->next );
	}while( LIST_ATROOT( ROOT_P , RET_CURR(ROOT_P) ) );
	return ;
}

inline void PREV_CURR( LIST_ROOT * ROOT_P){

	ASSERT_ALARM( ROOT_P );
	do{
		SET_CURR( ROOT_P , RET_CURR(ROOT_P)->prev );
	}while( LIST_ATROOT( ROOT_P , RET_CURR(ROOT_P) ) );
	return ;
}

inline int LIST_FOREACH( LIST_ROOT * ROOT_P , FOREACH_FUNCTION FUNC_P , void * DATA_P ){

	ASSERT_ALARM( ROOT_P );
	ASSERT_ALARM( FUNC_P );

	LIST_NODE * ITEM_P , ITEM;
	if( LIST_EMPTY( ROOT_P ) ){
		return -1;
	}
	
	for( ITEM_P = ROOT_P->root.next ; 
	     ITEM_P != &ROOT_P->root ;
	     ITEM_P = ITEM.next ){

		ITEM = *ITEM_P;
		FUNC_P( ROOT_P , ITEM_P , DATA );

	}
	return ;
}

inline LIST_NOTE * LIST_ADD_ASSIGN( void * ITEM_P , unsigned int SIZE , int TYPE ){
	
	LIST_NODE * ITEM_TMP_P;

	ASSERT_ALARM( ITEM_P );
	ASSERT_ALARM( SIZE );

	MALLOC_ITEM( ITEM_TMP_P , sizeof( LIST_NODE ) );
	CREATE_COPY_ITEM( ITEM_TMP_P->data , ITEM_P , SIZE );

	ITEM_TMP_P->size = SIZE;
	ITEM_TMP_P->type = TYPE;
	
	return ITEM_TMP_P;
}
inline int LIST_ADD_LINK_BEFORE( LIST_ROOT * ROOT_P , LIST_NODE * ITEM_BEFORE_P , LIST_NODE * ITEM_P ){
	ITEM_P->prev = ITEM_BEFORE_P;
	ITEM_P->next = ITEM_BEFORE_P->next;
	ITEM_BEFORE_P
	ITEM_BEFOER_P
	LIST_INC_NODE( ROOT_P );
}
inline int LIST_ADD_HEAD( LIST_ROOT * ROOT_P , void * ITEM_P , unsigned int SIZE , int TYPE ){

	LIST_NODE * ITEM_TMP_P = LIST_ADD_INNER( ROOT_P , ITEM_P , SIZE , TYPE );

	ITEM_TMP_P->prev = ROOT_P->root;
	ITEM_TMP_P->next = ROOT_P->root.next;
	ROOT_P->root.next->prev = ITEM_TMP_P;
	ROOT_P->root.next = ITEM_TMP_P;

	return ;
}
inline int LIST_ADD_TAIL( LIST_ROOT * ROOT_P , void * ITEM_P , unsigned int SIZE , int TYPE ){

	LIST_NODE * ITEM_TMP_P = LIST_ADD_INNER( ROOT_P , ITEM_P , SIZE , TYPE );

	ITEM_TMP_P->prev = ROOT_P->root.prev;
	ITEM_TMP_P->next = ROOT_P->root;
	ROOT_P->root.prev->next = ITEM_TMP_P;
	ROOT_P->root.prev = ITEM_TMP_P;

	return ;
}
inline int LIST_ADD_BEFORE( LIST_ROOT * ROOT_P , LIST_NODE * ITEM_SRC_P , void * ITEM_P , unsigned int SIZE , int TYPE ){
	
	LIST_NODE * ITEM_TMP_P = LIST_ADD_INNER( ROOT_P , ITEM_P , SIZE , TYPE );

	if( LIST_ATROOT( ROOT_P , ITEM_SRC_P ) ){
		LIST_ADD_HEAD( ROOT_P , ITEM_P , SIZE , TYPE );
		goto out;
	}

	LIST_NODE * __ITEM_P_TMP;
out:	
	return ;
}
inline int LIST_ADD_AFTER( LIST_ROOT * ROOT_P , LIST_NODE * ITEM_SRC_P , void * ITEM_P , unsigned int SIZE , int type ){
	LIST_NODE * ITEM_TMP_P;

	ITEM_TMP_P = LIST_ADD_INNER( ROOT_P , ITEM_P , SIZE , TYPE );
	return ;
}
inline void LIST_DEL_INNER( LIST_ROOT * ROOT_P , LIST_NODE * ITEM){
}
inline int LIST_DEL_HEAD( LIST_ROOT * ROOT_P ){
	ASSERT_ALARM( ROOT_P );
	if( LIST_EMPTY( ROOT_P ) ){
		goto out;
	}
	LIST_NODE * head_tmp = ROOT_P->root.next;
	
	ROOT_P->root.next = ROOT_P->root.next->next;
	ROOT_P->root.next->prev = &ROOT_P->root;
	FREE_ITEM( head_tmp->data  );
	FREE_ITEM( head_tmp );
	
	LIST_DEC_NODE( ROOT_P );

out:
	return ;
}
inline int LIST_DEL_TAIL( LIST_ROOT * ROOT ){
	
	ASSERT_ALARM( ROOT_P );
	if( LIST_EMPTY( ROOT_P ) ){
		goto out;
	}
	
	LIST_NODE * tail_tmp = ROOT_P->root.prev;
	ROOT_P->root.prev = ROOT_P->root.prev->prev;
	ROOT_P->root.prev->next = &ROOT_P->root;

	FREE_ITEM( tail_tmp->data );
	FREE_ITEM( tail_tmp );
	LIST_DEC_NODE( ROOT_P );
out:
	return ;
}

inline int 		del_item_inner	( LIST_ROOT * root , LIST_NODE * node_p , void * data ){

	return ;
}
inline int 		LIST_DEL_ITEM	( LIST_ROOT * ROOT , LIST_NODE * ITEM_P ){

	return ;
}

inline int LIST_PREV_NORET( LIST_ROOT * ROOT_P ){
	if( LIST_EMPTY( ROOT_P ) ){
		goto out;
	}
	PREV_CURR( ROOT_P );
	if( LIST_ATROOT( ROOT_P , RET_CURR( ROOT_P ) ) ){
		PREV_CURR( ROOT_P )
	}
out:
	return ;
}

inline LIST_NODE *LIST_PREV( LIST_ROOT * ROOT , LIST_NODE ** ITEM_P_P ){

	ASSERT_ALARM( ITEM_P_P );
	LIST_PREV_NORET( ROOT_P );
	*(ITEM_P_P) = RET_CURR( ROOT_P );
	return ;
}
inline int LIST_NEXT_NORET( LIST_ROOT * ROOT_P ){
	if( LIST_EMPTY( ROOT_P ) ){
		goto out;
	}
	NEXT_CURR( ROOT_P );
	if( LIST_ATROOT( ROOT_P , RET_CURR( ROOT_P ) ) ){
		NEXT_CURR( ROOT_P )
	}
out:
	return ;
}

inline LIST_NODE *LIST_NEXT( LIST_ROOT * ROOT , LIST_NODE ** ITEM_P_P ){

	ASSERT_ALARM( ITEM_P_P );
	LIST_NEXT_NORET( ROOT_P );
	*(ITEM_P_P) = RET_CURR( ROOT_P );
	return ;
}
inline int LIST_LOCATE_LOOP( LIST_ROOT * ROOT , unsigned int NUM , LIST_NODE ** ITEM_P_P ){
	
	ASSERT_ALARM( ITEM_P_P );
	
	if( 0 == NUM ){
		goto out;
	}

	int __LIST_NUM_TEMP;
	
	RESET_CURR( ROOT_P );
	
	for( __LIST_NUM_TEMP = 0;
	     __LIST_NUM_TEMP < NUM ;
	     __LIST_NUM_TEMP ++ ){
		LIST_NEXT_NORET( ROOT_P );
	}

	*ITEM_P_P = RET_CURR( ROOT_P );
	return ;
}
/*end LIST_FUNC */

#endif /*end LIST_MACRO */ 

#ifdef __cplusplus
}
#endif

#endif
